package com.example.kotlindemo.demo

/**
 * Author 87231
 * 2022/8/16 23:44
 *
 * Unit8
 * describe：扩展
 * (1.kotlin可以对一个类的属性和方法进行扩展 2.扩展是一种静态行为，对被扩展的类的代码本身不造成任何影响)
 * 1.扩展函数
 * 2.扩展函数时静态解析的
 * 3.扩展一个空对象
 * 4.伴生对象的扩展
 * 5.扩展的作用域
 * 6.扩展声明为成员
 **/
class Unit8 {
    /**
     * 一、扩展函数
     * 格式：
     * fun receiverType.functionName(param){
     * receiverType:函数的接收者
     * functionName：函数名称
     * param：参数，可以为null
     * }
     * 1.在已有的类中添加新的方法，不会对原来的类进行修改
     */

    class A {
        fun foo() {
            println("A")
        }
    }

    class B {
        fun A.show() {//为A添加一个show函数
            println("A show")
        }

        fun test() {
            A().show()
        }
    }

    /**
     * 二、扩展函数时静态解析的
     * 1.扩展函数不是接受者类型的虚拟成员，在调用扩展函数的时候，具体被调用搞得时哪一个函数，
     * 由调用函数的对象表达式来决定，而不是动态类型决定
     *2.若拓展函数和成员函数一致的话则会优先使用成员函数
     */
    open class C
    class C1 : C()
    class C2 {
        fun C.foo() = "C"
        fun C1.foo() = "C1"
        fun foo(c: C) {
            println(c.foo())
        }

        fun foo1(c1: C1) {
            println(c1.foo())
        }

        fun test() {
            foo(C1())
            foo(C())
            foo1(C1())
        }
    }

    class F {
        fun foo() {//优先使用成员函数
            println("成员函数")
        }
    }

    class F1 {
        fun F.foo() {
            println("扩展函数")
        }

        fun test() {
            F().foo()
        }
    }

    /**
     * 三、扩展一个空对象
     * 1.在扩展函数里可以通过this来判断接受者是否为空，这样即使接受者为null，也可以调用扩展函数
     * 2.kotlin也支持属性的扩展，但是不允许定义在函数中。
     * 3.扩展的属性不能够被初始化，只能通过setter和getter来定义
     */
    class G {
        fun Any?.show(): String {
            if (this == null) return "null"
            return toString()
        }

        fun test() {
            var a = "hello"
            println(a.show())
        }
    }

    class G1 {
        val G1.name: String
            get() = "haha"
    }

    /**
     * 四、伴生对象的扩展
     * 1.如果一个类有一个伴生对象，那么也可以为这个伴生对象进行扩展
     *
     */
    class H {
        companion object {
        }
    }

    class H1 {
        val H.Companion.name: String
            get() = "hah"

        fun H.Companion.foo() {
            println("伴生对象的扩展方法")
        }

        fun test() {
            H.Companion.foo()
            println("伴生对象的扩展参数为=${H.name}")
        }
    }
    /**
     * 五：扩展的作用域
     * 1.要使用所定义包之外的一个扩展, 通过import导入扩展的函数名进行使用
     */

    /**
     * 六、扩展声明为成员
     * 1.在一个类的内部可以为另一个类声明扩展
     * 分发接受者：为别的类进行扩展的类
     * 扩展接收者：被别的类扩展的类
     * 2.当分发者和接收者的方法名一样时，接收者的方法会被有限调用
     * 3.以成员的形式定义的扩展对象，可以声明为open，而且可以在子类中覆盖，也就是说，这类扩展函数的派发过程，针对分发接受者是虚拟的，但是针对扩展接受者仍然是静态的。
     *
     */
    class M {
        fun funM() {
            println("m")
        }
    }

    class N {
        fun funN() {
            println("n")
        }

        fun M.foo() {
            funM()//M().funM()
            funN()//N().funN()
        }

        fun test(m: M) {
            m.foo()
        }
    }

    //方法名相同
    class M1 {
        fun foo() {
            println("m1")
        }
    }

    class N1 {
        fun foo() {
            println("n1")
        }

        fun M1.show() {
            foo()//M().funM(),接受者的方法优先调用
            this@N1.foo()//N().funN()
        }

        fun test(m1: M1) {
            m1.foo()
        }
    }

    open class O//接受者
    class O1 : O()//结束者
    open class P {
        //分发者
        open fun O.foo() {
            println("O in P")
        }

        open fun O1.foo() {
            println("O1 in P")
        }

        fun test(o: O) {
            o.foo()
        }
    }

    class P1 : P() {
        //分发者
        override fun O.foo() {
            println("O in P1")
        }

        override fun O1.foo() {
            println("O1 in P1")
        }
    }


}